"""
请求钩子:
    可以对请求的各阶段进行监听, 方便开发者 针对请求完成一些统一的处理,以便减少重复代码,作用类比Django中的中间件

开发中中主要会用到以下四种请求钩子：
    before_request:
        每次执行视图函数之前调用
        对请求进行一些准备处理
        如果在该函数中返回了一个响应，视图函数将不再被调用
    after_request
        如果没有抛出错误，每次执行视图函数之后(已经包装为响应对象)调用
        在此函数中可以对响应值在返回之前做最后一步修改处理
        接受一个参数：包装好的响应对象
        需要将修改后的响应对象返回
    before_first_request
        web应用被第一次请求前调用
        可以进行web应用初始化处理
    teardown_request：
        每次执行视图函数之后调用
        无论是否出现异常都会执行, 一般用于请求收尾
        接受一个参数：错误信息，如果有相关错误抛出

请求钩子可以通过两种方式进行添加, 装饰器形式 或者 直接方法调用
"""
from flask import Flask, Response

app = Flask(__name__)


# 装饰器形式添加请求钩子
# 每次执行视图函数之前调用, 对请求进行一些准备处理, 如参数解析, 黑名单过滤, 数据统计等
@app.before_request     # 装饰器本质 prepare = app.before_request(prepare)
def prepare():
    print("每次执行视图函数之前调用 before_request")


# 每次执行视图函数之后(已经包装为响应对象)调用, 对响应进行一些加工处理, 如设置统一响应头, 设置数据的外层包装
@app.after_request
# 必须定义形参接收响应对象
# def process(response):或
def process(response: Response):
    print("没有抛出错误,每次执行视图函数之后调用 after_request")
    # print(response.headers)
    # print(response.data)
    # print(response.status_code)
    return response


# web应用被第一次请求前调用, 可以进行web应用初始化处理, 如数据库连接
@app.before_first_request
def initial():
    print("web应用被第一次请求前调用 before_first_request")


# 每次执行视图函数之后调用, 无论是否出现异常都会执行, 一般用于请求收尾, 如资源回收, 异常统计
@app.teardown_request   # 测试时不要开启调试模式
# 必须定义形参来接收具体错误信息, 如果没有错误, error=None
def request_handle(error):
    print('每次执行视图函数之后调用 teardown_request : %s' % error)


# 直接方法调用添加请求钩子
# app.teardown_request(request_handle)


@app.route('/')
def index():
    print("执行视图")
    # 模拟异常
    a = 1 / 0
    return "请求钩子"


if __name__ == '__main__':
    # 想要测试teardown_request 必须关闭调试模式 debug=True
    app.run()
